const { createServer } = require('http')
const crypto = require('crypto')
const server = createServer()
server.listen(3000)
server.on('upgrade', (req, socket) => {
    if (req.headers["upgrade"] !== "websocket") {
        socket.end("HTTP/1.1 400 Bad Request");
        return;
    }
    /****************************** 握手部分 *****************************************/
    const hash = crypto.createHash('sha1')
        .update(req.headers['sec-websocket-key'] + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
        .digest('base64')
    const headers = [
        'HTTP/1.1 101 Switching Protocols',
        'Upgrade: websocket',
        'Connection: Upgrade',
        'Sec-WebSocket-Accept: '+ hash
    ].concat('', '').join('\r\n')
    // 子协议
    const protocol = req.headers["sec-websocket-protocol"];
    const protocols = !protocol ? [] : protocol.split(",").map((s) => s.trim());
    // 简单起见，我们仅判断是否含有JSON子协议
    if (protocols.includes("json")) {
        headers.push(`Sec-WebSocket-Protocol: json`);
    }
    socket.write(headers)

    /****************************** 传输数据部分 *****************************************/
    socket.on("data", (buffer) => {
        const message = parseMessage(buffer)
        console.log(message)
        socket.write(reply('服务端收到消息：'+message))
    })
})

function parseMessage(buffer){
    const firstByte = buffer[0]
    const isEnd = firstByte >>> 7 & 0x01 === 1 // 判断第一位是不是1
    const opCode = firstByte &  0b00001111 // 取出后四位
    // 只处理文本数据
    if(opCode !== 0x01){
        return
    }
    const secondByte = buffer[1]
    const isMasked = secondByte >>> 7 & 0x01 === 1 // 获取 mask
    const payloadLen = secondByte & 0b01111111 // 获取传输内容长度
    if(!isMasked){
        return
    }

    // 获取掩码
    let mask = []
    let offset = 2
    if(payloadLen < 126){
        // 后面的4个字节是掩码
        mask = buffer.slice(2,2+4)
        offset += 4
    }else if(payloadLen === 126){
        // 后面的两个字节是长度，长度后面的4个字节才是掩码
        mask = buffer.slice(2 + 2, 2 + 2 + 4);
        offset += 6
    }else{
         // 如果是 127，后面8个字节是长度，长度后面才是掩码
         mask = buffer.slice(2 + 8, 2 + 8 + 4);
         offset += 12
    }
    
    // 解码运算
    const paylaodBuffer = buffer.slice(offset)
    const content = []
    let j = 0
    for(let i = 0;i<paylaodBuffer.length;i++){
        j = i % 4
        content.push(paylaodBuffer[i] ^ mask[j])
    }
    return Buffer.from(content).toString()
}

function reply(text){
    const textByteLength = Buffer.byteLength(text)
    // payload len 127 不处理
    let byteCountLength = textByteLength < 126 ? 0 : 2
    // 数据帧长度：
    //   第1个字节存储 fin、resv，opcode
    //   第2个字节存储 masked 和小于 126 时的长度 
    //   textByteLength 个字节存储内容
    //   byteCountLength 个字节存储内容大于 125 时的长度
    const buffer = Buffer.alloc(2 + byteCountLength + textByteLength);

    // 设置帧头
    buffer.writeUInt8(0b10000001, 0);
    buffer.writeUInt8(textByteLength, 1);

   // 内容大于 125 字节
    let offset = 2
    if (byteCountLength > 0) {
        buffer.writeUInt16BE(jsonByteLength, 2)
        offset += byteCountLength
    }
    buffer.write(text, offset);
    return buffer
}